1   /*
2    * Copyright (C) 2009 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.truth.Truth.assertThat;
20  
21  import com.google.common.annotations.GwtCompatible;
22  import com.google.common.annotations.GwtIncompatible;
23  import com.google.common.base.Joiner;
24  import com.google.common.collect.ImmutableSortedMap.Builder;
25  import com.google.common.collect.testing.ListTestSuiteBuilder;
26  import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
27  import com.google.common.collect.testing.SortedMapInterfaceTest;
28  import com.google.common.collect.testing.features.CollectionFeature;
29  import com.google.common.collect.testing.features.CollectionSize;
30  import com.google.common.collect.testing.features.MapFeature;
31  import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapEntryListGenerator;
32  import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapGenerator;
33  import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapKeyListGenerator;
34  import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapValueListGenerator;
35  import com.google.common.testing.NullPointerTester;
36  import com.google.common.testing.SerializableTester;
37  
38  import junit.framework.Test;
39  import junit.framework.TestCase;
40  import junit.framework.TestSuite;
41  
42  import java.io.Serializable;
43  import java.util.Collections;
44  import java.util.Comparator;
45  import java.util.LinkedHashMap;
46  import java.util.Map;
47  import java.util.Map.Entry;
48  import java.util.SortedMap;
49  
50  /**
51   * Tests for {@link ImmutableSortedMap}.
52   *
53   * @author Kevin Bourrillion
54   * @author Jesse Wilson
55   * @author Jared Levy
56   */
57  @GwtCompatible(emulated = true)
58  public class ImmutableSortedMapTest extends TestCase {
59    // TODO: Avoid duplicating code in ImmutableMapTest
60  
61    @GwtIncompatible("suite")
62    public static Test suite() {
63      TestSuite suite = new TestSuite();
64      suite.addTestSuite(ImmutableSortedMapTest.class);
65  
66      suite.addTest(NavigableMapTestSuiteBuilder.using(
67          new ImmutableSortedMapGenerator())
68          .withFeatures(
69              CollectionSize.ANY,
70              CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS,
71              CollectionFeature.KNOWN_ORDER,
72              MapFeature.REJECTS_DUPLICATES_AT_CREATION,
73              MapFeature.ALLOWS_ANY_NULL_QUERIES)
74          .named("ImmutableSortedMap")
75          .createTestSuite());
76  
77      suite.addTest(ListTestSuiteBuilder.using(
78          new ImmutableSortedMapEntryListGenerator())
79          .named("ImmutableSortedMap.entrySet.asList")
80          .withFeatures(CollectionSize.ANY,
81              CollectionFeature.SERIALIZABLE,
82              CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
83              CollectionFeature.ALLOWS_NULL_QUERIES)
84          .createTestSuite());
85  
86      suite.addTest(ListTestSuiteBuilder.using(
87          new ImmutableSortedMapKeyListGenerator())
88          .named("ImmutableSortedMap.keySet.asList")
89          .withFeatures(CollectionSize.ANY,
90              CollectionFeature.SERIALIZABLE,
91              CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
92              CollectionFeature.ALLOWS_NULL_QUERIES)
93          .createTestSuite());
94  
95      suite.addTest(ListTestSuiteBuilder.using(
96          new ImmutableSortedMapValueListGenerator())
97          .named("ImmutableSortedMap.values.asList")
98          .withFeatures(CollectionSize.ANY,
99              CollectionFeature.SERIALIZABLE,
100             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
101             CollectionFeature.ALLOWS_NULL_QUERIES)
102         .createTestSuite());
103 
104     return suite;
105   }
106 
107   public abstract static class AbstractMapTests<K, V>
108       extends SortedMapInterfaceTest<K, V> {
109     public AbstractMapTests() {
110       super(false, false, false, false, false);
111     }
112 
113     @Override protected SortedMap<K, V> makeEmptyMap() {
114       throw new UnsupportedOperationException();
115     }
116 
117     private static final Joiner joiner = Joiner.on(", ");
118 
119     @Override protected void assertMoreInvariants(Map<K, V> map) {
120       // TODO: can these be moved to MapInterfaceTest?
121       for (Entry<K, V> entry : map.entrySet()) {
122         assertEquals(entry.getKey() + "=" + entry.getValue(),
123             entry.toString());
124       }
125 
126       assertEquals("{" + joiner.join(map.entrySet()) + "}",
127           map.toString());
128       assertEquals("[" + joiner.join(map.entrySet()) + "]",
129           map.entrySet().toString());
130       assertEquals("[" + joiner.join(map.keySet()) + "]",
131           map.keySet().toString());
132       assertEquals("[" + joiner.join(map.values()) + "]",
133           map.values().toString());
134 
135       assertEquals(Sets.newHashSet(map.entrySet()), map.entrySet());
136       assertEquals(Sets.newHashSet(map.keySet()), map.keySet());
137     }
138   }
139 
140   public static class MapTests extends AbstractMapTests<String, Integer> {
141     @Override protected SortedMap<String, Integer> makeEmptyMap() {
142       return ImmutableSortedMap.of();
143     }
144 
145     @Override protected SortedMap<String, Integer> makePopulatedMap() {
146       return ImmutableSortedMap.of("one", 1, "two", 2, "three", 3);
147     }
148 
149     @Override protected String getKeyNotInPopulatedMap() {
150       return "minus one";
151     }
152 
153     @Override protected Integer getValueNotInPopulatedMap() {
154       return -1;
155     }
156   }
157 
158   public static class SingletonMapTests
159       extends AbstractMapTests<String, Integer> {
160     @Override protected SortedMap<String, Integer> makePopulatedMap() {
161       return ImmutableSortedMap.of("one", 1);
162     }
163 
164     @Override protected String getKeyNotInPopulatedMap() {
165       return "minus one";
166     }
167 
168     @Override protected Integer getValueNotInPopulatedMap() {
169       return -1;
170     }
171   }
172 
173   @GwtIncompatible("SerializableTester")
174   public static class ReserializedMapTests
175       extends AbstractMapTests<String, Integer> {
176     @Override protected SortedMap<String, Integer> makePopulatedMap() {
177       return SerializableTester.reserialize(
178           ImmutableSortedMap.of("one", 1, "two", 2, "three", 3));
179     }
180 
181     @Override protected String getKeyNotInPopulatedMap() {
182       return "minus one";
183     }
184 
185     @Override protected Integer getValueNotInPopulatedMap() {
186       return -1;
187     }
188   }
189 
190   public static class HeadMapTests extends AbstractMapTests<String, Integer> {
191     @Override protected SortedMap<String, Integer> makePopulatedMap() {
192       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
193           .headMap("d");
194     }
195 
196     @Override protected String getKeyNotInPopulatedMap() {
197       return "d";
198     }
199 
200     @Override protected Integer getValueNotInPopulatedMap() {
201       return 4;
202     }
203   }
204 
205   public static class HeadMapInclusiveTests extends AbstractMapTests<String, Integer> {
206     @Override protected SortedMap<String, Integer> makePopulatedMap() {
207       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
208           .headMap("c", true);
209     }
210 
211     @Override protected String getKeyNotInPopulatedMap() {
212       return "d";
213     }
214 
215     @Override protected Integer getValueNotInPopulatedMap() {
216       return 4;
217     }
218   }
219 
220   public static class TailMapTests extends AbstractMapTests<String, Integer> {
221     @Override protected SortedMap<String, Integer> makePopulatedMap() {
222       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
223           .tailMap("b");
224     }
225 
226     @Override protected String getKeyNotInPopulatedMap() {
227       return "a";
228     }
229 
230     @Override protected Integer getValueNotInPopulatedMap() {
231       return 1;
232     }
233   }
234 
235   public static class TailExclusiveMapTests extends AbstractMapTests<String, Integer> {
236     @Override protected SortedMap<String, Integer> makePopulatedMap() {
237       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
238           .tailMap("a", false);
239     }
240 
241     @Override protected String getKeyNotInPopulatedMap() {
242       return "a";
243     }
244 
245     @Override protected Integer getValueNotInPopulatedMap() {
246       return 1;
247     }
248   }
249 
250   public static class SubMapTests extends AbstractMapTests<String, Integer> {
251     @Override protected SortedMap<String, Integer> makePopulatedMap() {
252       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
253           .subMap("b", "d");
254     }
255 
256     @Override protected String getKeyNotInPopulatedMap() {
257       return "a";
258     }
259 
260     @Override protected Integer getValueNotInPopulatedMap() {
261       return 4;
262     }
263   }
264 
265   public static class CreationTests extends TestCase {
266     public void testEmptyBuilder() {
267       ImmutableSortedMap<String, Integer> map
268           = ImmutableSortedMap.<String, Integer>naturalOrder().build();
269       assertEquals(Collections.<String, Integer>emptyMap(), map);
270     }
271 
272     public void testSingletonBuilder() {
273       ImmutableSortedMap<String, Integer> map
274           = ImmutableSortedMap.<String, Integer>naturalOrder()
275               .put("one", 1)
276               .build();
277       assertMapEquals(map, "one", 1);
278     }
279 
280     public void testBuilder() {
281       ImmutableSortedMap<String, Integer> map
282           = ImmutableSortedMap.<String, Integer>naturalOrder()
283               .put("one", 1)
284               .put("two", 2)
285               .put("three", 3)
286               .put("four", 4)
287               .put("five", 5)
288               .build();
289       assertMapEquals(map,
290           "five", 5, "four", 4, "one", 1, "three", 3, "two", 2);
291     }
292 
293     public void testBuilder_withImmutableEntry() {
294       ImmutableSortedMap<String, Integer> map =
295           ImmutableSortedMap.<String, Integer>naturalOrder()
296               .put(Maps.immutableEntry("one", 1))
297               .build();
298       assertMapEquals(map, "one", 1);
299     }
300 
301     public void testBuilder_withImmutableEntryAndNullContents() {
302       Builder<String, Integer> builder =
303           ImmutableSortedMap.naturalOrder();
304       try {
305         builder.put(Maps.immutableEntry("one", (Integer) null));
306         fail();
307       } catch (NullPointerException expected) {
308       }
309       try {
310         builder.put(Maps.immutableEntry((String) null, 1));
311         fail();
312       } catch (NullPointerException expected) {
313       }
314     }
315 
316     private static class StringHolder {
317       String string;
318     }
319 
320     public void testBuilder_withMutableEntry() {
321       ImmutableSortedMap.Builder<String, Integer> builder =
322           ImmutableSortedMap.naturalOrder();
323       final StringHolder holder = new StringHolder();
324       holder.string = "one";
325       Entry<String, Integer> entry = new AbstractMapEntry<String, Integer>() {
326         @Override public String getKey() {
327           return holder.string;
328         }
329         @Override public Integer getValue() {
330           return 1;
331         }
332       };
333 
334       builder.put(entry);
335       holder.string = "two";
336       assertMapEquals(builder.build(), "one", 1);
337     }
338 
339     public void testBuilderPutAllWithEmptyMap() {
340       ImmutableSortedMap<String, Integer> map
341           = ImmutableSortedMap.<String, Integer>naturalOrder()
342               .putAll(Collections.<String, Integer>emptyMap())
343               .build();
344       assertEquals(Collections.<String, Integer>emptyMap(), map);
345     }
346 
347     public void testBuilderPutAll() {
348       Map<String, Integer> toPut = new LinkedHashMap<String, Integer>();
349       toPut.put("one", 1);
350       toPut.put("two", 2);
351       toPut.put("three", 3);
352       Map<String, Integer> moreToPut = new LinkedHashMap<String, Integer>();
353       moreToPut.put("four", 4);
354       moreToPut.put("five", 5);
355 
356       ImmutableSortedMap<String, Integer> map
357           = ImmutableSortedMap.<String, Integer>naturalOrder()
358               .putAll(toPut)
359               .putAll(moreToPut)
360               .build();
361       assertMapEquals(map,
362           "five", 5, "four", 4, "one", 1, "three", 3, "two", 2);
363     }
364 
365     public void testBuilderReuse() {
366       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
367       ImmutableSortedMap<String, Integer> mapOne = builder
368           .put("one", 1)
369           .put("two", 2)
370           .build();
371       ImmutableSortedMap<String, Integer> mapTwo = builder
372           .put("three", 3)
373           .put("four", 4)
374           .build();
375 
376       assertMapEquals(mapOne, "one", 1, "two", 2);
377       assertMapEquals(mapTwo, "four", 4, "one", 1, "three", 3, "two", 2);
378     }
379 
380     public void testBuilderPutNullKey() {
381       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
382       try {
383         builder.put(null, 1);
384         fail();
385       } catch (NullPointerException expected) {
386       }
387     }
388 
389     public void testBuilderPutNullValue() {
390       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
391       try {
392         builder.put("one", null);
393         fail();
394       } catch (NullPointerException expected) {
395       }
396     }
397 
398     public void testBuilderPutNullKeyViaPutAll() {
399       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
400       try {
401         builder.putAll(Collections.<String, Integer>singletonMap(null, 1));
402         fail();
403       } catch (NullPointerException expected) {
404       }
405     }
406 
407     public void testBuilderPutNullValueViaPutAll() {
408       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
409       try {
410         builder.putAll(Collections.<String, Integer>singletonMap("one", null));
411         fail();
412       } catch (NullPointerException expected) {
413       }
414     }
415 
416     public void testPuttingTheSameKeyTwiceThrowsOnBuild() {
417       Builder<String, Integer> builder
418           = ImmutableSortedMap.<String, Integer>naturalOrder()
419               .put("one", 1)
420               .put("one", 2); // throwing on this line would be even better
421 
422       try {
423         builder.build();
424         fail();
425       } catch (IllegalArgumentException expected) {
426       }
427     }
428 
429     public void testOf() {
430       assertMapEquals(
431           ImmutableSortedMap.of("one", 1),
432           "one", 1);
433       assertMapEquals(
434           ImmutableSortedMap.of("one", 1, "two", 2),
435           "one", 1, "two", 2);
436       assertMapEquals(
437           ImmutableSortedMap.of("one", 1, "two", 2, "three", 3),
438           "one", 1, "three", 3, "two", 2);
439       assertMapEquals(
440           ImmutableSortedMap.of("one", 1, "two", 2, "three", 3, "four", 4),
441           "four", 4, "one", 1, "three", 3, "two", 2);
442       assertMapEquals(
443           ImmutableSortedMap.of(
444               "one", 1, "two", 2, "three", 3, "four", 4, "five", 5),
445           "five", 5, "four", 4, "one", 1, "three", 3, "two", 2);
446     }
447 
448     public void testOfNullKey() {
449       Integer n = null;
450       try {
451         ImmutableSortedMap.of(n, 1);
452         fail();
453       } catch (NullPointerException expected) {
454       }
455 
456       try {
457         ImmutableSortedMap.of("one", 1, null, 2);
458         fail();
459       } catch (NullPointerException expected) {
460       }
461     }
462 
463     public void testOfNullValue() {
464       try {
465         ImmutableSortedMap.of("one", null);
466         fail();
467       } catch (NullPointerException expected) {
468       }
469 
470       try {
471         ImmutableSortedMap.of("one", 1, "two", null);
472         fail();
473       } catch (NullPointerException expected) {
474       }
475     }
476 
477     public void testOfWithDuplicateKey() {
478       try {
479         ImmutableSortedMap.of("one", 1, "one", 1);
480         fail();
481       } catch (IllegalArgumentException expected) {
482       }
483     }
484 
485     public void testCopyOfEmptyMap() {
486       ImmutableSortedMap<String, Integer> copy
487           = ImmutableSortedMap.copyOf(Collections.<String, Integer>emptyMap());
488       assertEquals(Collections.<String, Integer>emptyMap(), copy);
489       assertSame(copy, ImmutableSortedMap.copyOf(copy));
490       assertSame(Ordering.natural(), copy.comparator());
491     }
492 
493     public void testCopyOfSingletonMap() {
494       ImmutableSortedMap<String, Integer> copy
495           = ImmutableSortedMap.copyOf(Collections.singletonMap("one", 1));
496       assertMapEquals(copy, "one", 1);
497       assertSame(copy, ImmutableSortedMap.copyOf(copy));
498       assertSame(Ordering.natural(), copy.comparator());
499     }
500 
501     public void testCopyOf() {
502       Map<String, Integer> original = new LinkedHashMap<String, Integer>();
503       original.put("one", 1);
504       original.put("two", 2);
505       original.put("three", 3);
506 
507       ImmutableSortedMap<String, Integer> copy
508           = ImmutableSortedMap.copyOf(original);
509       assertMapEquals(copy, "one", 1, "three", 3, "two", 2);
510       assertSame(copy, ImmutableSortedMap.copyOf(copy));
511       assertSame(Ordering.natural(), copy.comparator());
512     }
513 
514     public void testCopyOfExplicitComparator() {
515       Comparator<String> comparator = Ordering.natural().reverse();
516       Map<String, Integer> original = new LinkedHashMap<String, Integer>();
517       original.put("one", 1);
518       original.put("two", 2);
519       original.put("three", 3);
520 
521       ImmutableSortedMap<String, Integer> copy
522           = ImmutableSortedMap.copyOf(original, comparator);
523       assertMapEquals(copy, "two", 2, "three", 3, "one", 1);
524       assertSame(copy, ImmutableSortedMap.copyOf(copy, comparator));
525       assertSame(comparator, copy.comparator());
526     }
527 
528     public void testCopyOfImmutableSortedSetDifferentComparator() {
529       Comparator<String> comparator = Ordering.natural().reverse();
530       Map<String, Integer> original
531           = ImmutableSortedMap.of("one", 1, "two", 2, "three", 3);
532       ImmutableSortedMap<String, Integer> copy
533           = ImmutableSortedMap.copyOf(original, comparator);
534       assertMapEquals(copy, "two", 2, "three", 3, "one", 1);
535       assertSame(copy, ImmutableSortedMap.copyOf(copy, comparator));
536       assertSame(comparator, copy.comparator());
537     }
538 
539     public void testCopyOfSortedNatural() {
540       SortedMap<String, Integer> original = Maps.newTreeMap();
541       original.put("one", 1);
542       original.put("two", 2);
543       original.put("three", 3);
544 
545       ImmutableSortedMap<String, Integer> copy
546           = ImmutableSortedMap.copyOfSorted(original);
547       assertMapEquals(copy, "one", 1, "three", 3, "two", 2);
548       assertSame(copy, ImmutableSortedMap.copyOfSorted(copy));
549       assertSame(Ordering.natural(), copy.comparator());
550     }
551 
552     public void testCopyOfSortedExplicit() {
553       Comparator<String> comparator = Ordering.natural().reverse();
554       SortedMap<String, Integer> original = Maps.newTreeMap(comparator);
555       original.put("one", 1);
556       original.put("two", 2);
557       original.put("three", 3);
558 
559       ImmutableSortedMap<String, Integer> copy
560           = ImmutableSortedMap.copyOfSorted(original);
561       assertMapEquals(copy, "two", 2, "three", 3, "one", 1);
562       assertSame(copy, ImmutableSortedMap.copyOfSorted(copy));
563       assertSame(comparator, copy.comparator());
564     }
565 
566     private static class IntegerDiv10 implements Comparable<IntegerDiv10> {
567       final int value;
568 
569       IntegerDiv10(int value) {
570         this.value = value;
571       }
572 
573       @Override
574       public int compareTo(IntegerDiv10 o) {
575         return value / 10 - o.value / 10;
576       }
577 
578       @Override public String toString() {
579         return Integer.toString(value);
580       }
581     }
582 
583     public void testCopyOfDuplicateKey() {
584       Map<IntegerDiv10, String> original = ImmutableMap.of(
585           new IntegerDiv10(3), "three",
586           new IntegerDiv10(20), "twenty",
587           new IntegerDiv10(11), "eleven",
588           new IntegerDiv10(35), "thirty five",
589           new IntegerDiv10(12), "twelve"
590       );
591 
592       try {
593         ImmutableSortedMap.copyOf(original);
594         fail("Expected IllegalArgumentException");
595       } catch (IllegalArgumentException expected) {
596       }
597     }
598 
599     public void testImmutableMapCopyOfImmutableSortedMap() {
600       IntegerDiv10 three = new IntegerDiv10(3);
601       IntegerDiv10 eleven = new IntegerDiv10(11);
602       IntegerDiv10 twelve = new IntegerDiv10(12);
603       IntegerDiv10 twenty = new IntegerDiv10(20);
604       Map<IntegerDiv10, String> original = ImmutableSortedMap.of(
605           three, "three", eleven, "eleven", twenty, "twenty");
606       Map<IntegerDiv10, String> copy = ImmutableMap.copyOf(original);
607       assertTrue(original.containsKey(twelve));
608       assertFalse(copy.containsKey(twelve));
609     }
610 
611     public void testBuilderReverseOrder() {
612       ImmutableSortedMap<String, Integer> map
613           = ImmutableSortedMap.<String, Integer>reverseOrder()
614               .put("one", 1)
615               .put("two", 2)
616               .put("three", 3)
617               .put("four", 4)
618               .put("five", 5)
619               .build();
620       assertMapEquals(map,
621           "two", 2, "three", 3, "one", 1, "four", 4, "five", 5);
622       assertEquals(Ordering.natural().reverse(), map.comparator());
623     }
624 
625     public void testBuilderComparator() {
626       Comparator<String> comparator = Ordering.natural().reverse();
627       ImmutableSortedMap<String, Integer> map
628           = new ImmutableSortedMap.Builder<String, Integer>(comparator)
629               .put("one", 1)
630               .put("two", 2)
631               .put("three", 3)
632               .put("four", 4)
633               .put("five", 5)
634               .build();
635       assertMapEquals(map,
636           "two", 2, "three", 3, "one", 1, "four", 4, "five", 5);
637       assertSame(comparator, map.comparator());
638     }
639   }
640 
641   public void testNullGet() {
642     ImmutableSortedMap<String, Integer> map = ImmutableSortedMap.of("one", 1);
643     assertNull(map.get(null));
644   }
645 
646   @GwtIncompatible("NullPointerTester")
647   public void testNullPointers() {
648     NullPointerTester tester = new NullPointerTester();
649     tester.testAllPublicStaticMethods(ImmutableSortedMap.class);
650     tester.testAllPublicInstanceMethods(
651         ImmutableSortedMap.<String, Integer>naturalOrder());
652     tester.testAllPublicInstanceMethods(ImmutableSortedMap.of());
653     tester.testAllPublicInstanceMethods(ImmutableSortedMap.of("one", 1));
654     tester.testAllPublicInstanceMethods(
655         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3));
656   }
657 
658   private static <K, V> void assertMapEquals(Map<K, V> map,
659       Object... alternatingKeysAndValues) {
660     assertEquals(map.size(), alternatingKeysAndValues.length / 2);
661     int i = 0;
662     for (Entry<K, V> entry : map.entrySet()) {
663       assertEquals(alternatingKeysAndValues[i++], entry.getKey());
664       assertEquals(alternatingKeysAndValues[i++], entry.getValue());
665     }
666   }
667 
668   private static class IntHolder implements Serializable {
669     public int value;
670 
671     public IntHolder(int value) {
672       this.value = value;
673     }
674 
675     @Override public boolean equals(Object o) {
676       return (o instanceof IntHolder) && ((IntHolder) o).value == value;
677     }
678 
679     @Override public int hashCode() {
680       return value;
681     }
682 
683     private static final long serialVersionUID = 5;
684   }
685 
686   public void testMutableValues() {
687     IntHolder holderA = new IntHolder(1);
688     IntHolder holderB = new IntHolder(2);
689     Map<String, IntHolder> map
690         = ImmutableSortedMap.of("a", holderA, "b", holderB);
691     holderA.value = 3;
692     assertTrue(map.entrySet().contains(Maps.immutableEntry("a", new IntHolder(3))));
693     Map<String, Integer> intMap
694         = ImmutableSortedMap.of("a", 3, "b", 2);
695     assertEquals(intMap.hashCode(), map.entrySet().hashCode());
696     assertEquals(intMap.hashCode(), map.hashCode());
697   }
698 
699   @GwtIncompatible("SerializableTester")
700   public void testViewSerialization() {
701     Map<String, Integer> map
702         = ImmutableSortedMap.of("one", 1, "two", 2, "three", 3);
703     SerializableTester.reserializeAndAssert(map.entrySet());
704     SerializableTester.reserializeAndAssert(map.keySet());
705     assertEquals(Lists.newArrayList(map.values()),
706         Lists.newArrayList(SerializableTester.reserialize(map.values())));
707   }
708 
709   @SuppressWarnings("unchecked") // varargs
710   public void testHeadMapInclusive() {
711     Map<String, Integer> map =
712         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).headMap("three", true);
713     assertThat(map.entrySet()).has().exactly(
714         Maps.immutableEntry("one", 1),
715         Maps.immutableEntry("three", 3)).inOrder();
716   }
717 
718   @SuppressWarnings("unchecked") // varargs
719   public void testHeadMapExclusive() {
720     Map<String, Integer> map =
721         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).headMap("three", false);
722     assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1)).inOrder();
723   }
724 
725   @SuppressWarnings("unchecked") // varargs
726   public void testTailMapInclusive() {
727     Map<String, Integer> map =
728         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).tailMap("three", true);
729     assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
730         Maps.immutableEntry("two", 2)).inOrder();
731   }
732 
733   @SuppressWarnings("unchecked") // varargs
734   public void testTailMapExclusive() {
735     Map<String, Integer> map =
736         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).tailMap("three", false);
737     assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("two", 2)).inOrder();
738   }
739 
740   @SuppressWarnings("unchecked") // varargs
741   public void testSubMapExclusiveExclusive() {
742     Map<String, Integer> map =
743         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", false, "two", false);
744     assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3)).inOrder();
745   }
746 
747   @SuppressWarnings("unchecked") // varargs
748   public void testSubMapInclusiveExclusive() {
749     Map<String, Integer> map =
750         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", true, "two", false);
751     assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
752         Maps.immutableEntry("three", 3)).inOrder();
753   }
754 
755   @SuppressWarnings("unchecked") // varargs
756   public void testSubMapExclusiveInclusive() {
757     Map<String, Integer> map =
758         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", false, "two", true);
759     assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
760         Maps.immutableEntry("two", 2)).inOrder();
761   }
762 
763   @SuppressWarnings("unchecked") // varargs
764   public void testSubMapInclusiveInclusive() {
765     Map<String, Integer> map =
766         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", true, "two", true);
767     assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
768         Maps.immutableEntry("three", 3), Maps.immutableEntry("two", 2)).inOrder();
769   }
770 
771   private static class SelfComparableExample implements Comparable<SelfComparableExample> {
772     @Override
773     public int compareTo(SelfComparableExample o) {
774       return 0;
775     }
776   }
777 
778   public void testBuilderGenerics_SelfComparable() {
779     ImmutableSortedMap.Builder<SelfComparableExample, Object> natural =
780         ImmutableSortedMap.naturalOrder();
781 
782     ImmutableSortedMap.Builder<SelfComparableExample, Object> reverse =
783         ImmutableSortedMap.reverseOrder();
784   }
785 
786   private static class SuperComparableExample extends SelfComparableExample {}
787 
788   public void testBuilderGenerics_SuperComparable() {
789     ImmutableSortedMap.Builder<SuperComparableExample, Object> natural =
790         ImmutableSortedMap.naturalOrder();
791 
792     ImmutableSortedMap.Builder<SuperComparableExample, Object> reverse =
793         ImmutableSortedMap.reverseOrder();
794   }
795 }